package com.ikingtech.platform.service.system.post.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ikingtech.framework.sdk.base.model.BatchParam;
import com.ikingtech.framework.sdk.base.model.DragOrderParam;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.event.TenantDeleteEvent;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.context.exception.FrameworkException;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.data.mybatisplus.helper.DragHelper;
import com.ikingtech.framework.sdk.data.mybatisplus.helper.DragHelperBuilder;
import com.ikingtech.framework.sdk.enums.common.DragTargetPositionEnum;
import com.ikingtech.framework.sdk.log.embedded.annotation.OperationLog;
import com.ikingtech.framework.sdk.post.api.PostApi;
import com.ikingtech.framework.sdk.post.api.PostUserApi;
import com.ikingtech.framework.sdk.post.model.PostDTO;
import com.ikingtech.framework.sdk.post.model.PostQueryParamDTO;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.platform.service.system.post.entity.PostDO;
import com.ikingtech.platform.service.system.post.exception.PostExceptionInfo;
import com.ikingtech.platform.service.system.post.service.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
@RequiredArgsConstructor
@ApiController(value = "/system/post", name = "系统管理-岗位管理", description = "系统管理-岗位管理")
public class PostController implements PostApi {

    private final PostRepository repo;

    private final PostUserApi postUserApi;

    /**
     * 添加岗位
     *
     * @param post 岗位DTO对象
     * @return 岗位ID的字符串
     */
    @Override
    @OperationLog(value = "新增岗位", dataId = "#_res.getData()")
    @Transactional(rollbackFor = Exception.class)
    public R<String> add(PostDTO post) {
        // 将岗位DTO对象转换为岗位DO对象
        PostDO entity = Tools.Bean.copy(post, PostDO.class);
        // 生成岗位ID
        entity.setId(Tools.Id.uuid());
        // 获取最大排序顺序
        entity.setSortOrder(this.getMaxSortOrder() + 1);
        // 设置租户代码
        entity.setTenantCode(Me.tenantCode());
        // 保存岗位DO对象
        this.repo.save(entity);
        // 返回岗位ID
        return R.ok(entity.getId());
    }

    /**
     * 删除操作
     *
     * @param id 要删除的数据的id
     * @return 删除结果
     */
    @Override
    @OperationLog(value = "删除角色")
    @Transactional(rollbackFor = Exception.class)
    public R<Object> delete(String id) {
        // 从数据库中删除指定id的数据
        this.repo.removeById(id);
        // 从用户接口中删除指定id的用户发布信息
        this.postUserApi.removeUserPost(id);
        return R.ok();
    }

    /**
     * 更新岗位
     *
     * @param post 岗位信息
     * @return 更新结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Object> update(PostDTO post) {
        // 检查岗位是否存在
        if (!this.repo.exists(Wrappers.<PostDO>lambdaQuery().eq(PostDO::getId, post.getId()))) {
            throw new FrameworkException(PostExceptionInfo.POST_NOT_FOUND);
        }
        // 更新岗位信息
        this.repo.updateById(Tools.Bean.copy(post, PostDO.class));
        return R.ok();
    }

    /**
     * 分页查询岗位
     *
     * @param queryParam 查询参数
     * @return 分页结果
     */
    @Override
    public R<List<PostDTO>> page(PostQueryParamDTO queryParam) {
        // 调用repo的page方法进行分页查询，并使用createWrapper方法创建封装对象
        // 将查询结果转换为PostDTO对象并返回
        return R.ok(PageResult.build(this.repo.page(new Page<>(queryParam.getPage(), queryParam.getRows()), PostRepository.createWrapper(queryParam, Me.tenantCode()))).convert(entity -> Tools.Bean.copy(entity, PostDTO.class)));
    }

    /**
     * 获取所有岗位对象
     *
     * @return 岗位列表
     */
    @Override
    public R<List<PostDTO>> all() {
        // 将repo中的List转换为PostDTO对象的List
        return R.ok(Tools.Coll.convertList(this.repo.list(Wrappers.<PostDO>lambdaQuery()
                .eq(PostDO::getTenantCode, Me.tenantCode())
                .orderByDesc(PostDO::getCreateTime)), entity -> Tools.Bean.copy(entity, PostDTO.class)));
    }

    /**
     * 根据ID查询岗位详情
     *
     * @param id 岗位ID
     * @return 岗位详情
     */
    @Override
    public R<PostDTO> detail(String id) {
        // 根据ID查询岗位实体
        PostDO entity = this.repo.getById(id);
        // 如果岗位实体为空，则抛出岗位未找到异常
        if (null == entity) {
            throw new FrameworkException(PostExceptionInfo.POST_NOT_FOUND);
        }
        // 返回岗位详情
        return R.ok(Tools.Bean.copy(entity, PostDTO.class));
    }


    /**
     * 根据ID批量查询岗位
     *
     * @param ids 批量ID
     * @return 查询结果
     */
    @Override
    public R<Map<String, PostDTO>> mapByIds(BatchParam<String> ids) {
        // 如果ID列表为空，则返回空的HashMap
        if (Tools.Coll.isBlank(ids.getList())) {
            return R.ok(new HashMap<>());
        }
        // 查询PostDO列表，根据ID进行查询，且租户代码相同
        return R.ok(Tools.Coll.convertMap(this.repo.list(Wrappers.<PostDO>lambdaQuery()
                .in(PostDO::getId, ids.getList())
                .eq(PostDO::getTenantCode, Me.tenantCode())), PostDO::getId, entity -> Tools.Bean.copy(entity, PostDTO.class)));
    }


    /**
     * 拖拽操作
     * @param dragParam 拖拽参数
     * @return 操作结果
     */
    @Override
    public R<Object> drag(DragOrderParam dragParam) {
        if (DragTargetPositionEnum.NONE.equals(dragParam.getPosition())) {
            return R.ok();
        }
        // 构建拖拽帮助类
        DragHelper<PostDO> dragHelper = DragHelperBuilder.builder(this::between)
                .which(dragParam.getParentId(), dragParam.getTargetParentId(), DragTargetPositionEnum.INNER.equals(dragParam.getPosition()))
                .currentNode(() -> this.repo.getById(dragParam.getCurrentId()))
                .targetNode(() -> this.repo.getById(dragParam.getTargetId()))
                .maxSortOrder(this::getMaxSortOrder)
                .beforeTarget(DragTargetPositionEnum.BEFORE.equals(dragParam.getPosition()))
                .build();
        // 执行拖拽操作并更新数据
        this.repo.updateBatchById(dragHelper.drag());
        return R.ok();
    }

    /**
     * 处理租户删除事件
     * @param event 租户删除事件对象
     */
    @EventListener
    public void tenantDeleteEventListener(TenantDeleteEvent event) {
        this.repo.remove(Wrappers.<PostDO>lambdaQuery().eq(PostDO::getTenantCode, event.getCode()));
    }

    private Integer getMaxSortOrder() {
        List<Number> orders = this.repo.listObjs(Wrappers.<PostDO>lambdaQuery()
                .select(PostDO::getSortOrder)
                .eq(PostDO::getTenantCode, Me.tenantCode())
                .orderByDesc(PostDO::getSortOrder));
        return Tools.Coll.isBlank(orders) ? 0 : orders.get(0).intValue();
    }

    private <T> List<PostDO> between(T start, T end) {
        return this.repo.list(Wrappers.<PostDO>lambdaQuery()
                .between(PostDO::getSortOrder, start, end)
                .eq(PostDO::getTenantCode, Me.tenantCode()));
    }
}
